﻿using System;
using System.Runtime.InteropServices;

namespace Useful.Reflection
{
    public abstract class BaseComLateBounding : IDisposable
    {
        public readonly object MISSING = Type.Missing;

        protected ComObject app = null;

        protected string _Host;

        protected BaseComLateBounding(string host)
        {
            _Host = host;
        }

        protected virtual void CreateInstance()
        {
            Type classType = Type.GetTypeFromCLSID(ComGuid, _Host); // Создание COM-объекта приложения

            object obj = Activator.CreateInstance(classType);
            //object obj = Activator.GetObject(Type.GetTypeFromCLSID(ComGuid, _Host, true), "Excel.Application");

            app = new ComObject(obj, "_APP_");
        }

        protected void DestroyInstance()
        {
            app.Dispose();
        }

        public void Destroy()
        {
            if (app != null)
            {
                DestroyCore();
                DestroyInstance();
            }
        }

        public void Dispose()
        {
            Destroy();
        }

        protected abstract Guid ComGuid { get; }
        protected abstract void DestroyCore();

        private static COMException GetCOMException(Exception ex)
        {
            COMException res = null;

            if (ex is COMException)
                res = (COMException)ex;
            else if (ex.InnerException != null)
                res = GetCOMException(ex.InnerException);

            return res;
        }

        public static bool IsComObjectAccessible(Exception ex)
        {
            COMException testException = GetCOMException(ex);

            if (testException != null)
                return (uint)testException.ErrorCode != 0x800706BA; // RPC-сервер не доступен
            else
                return true;
        }

        public static bool IsComObjectAccessible2(Exception ex)
        {
            COMException testException = GetCOMException(ex);

            if (testException != null)
                return (uint)testException.ErrorCode != 0x800706BA && (uint)testException.ErrorCode != 0x800706BE; // RPC-сервер не доступен
            else
                return true;
        }

        public static bool NeedReset(Exception ex)
        {
            COMException testException = GetCOMException(ex);

            if (testException != null)
                return testException.Message.Contains("IClassFactory") && testException.Message.Contains("800706be");
            else
                return false;
        }
    }
}
